스트림 API
✒️ 2025-05-15 10:39 내용 수정
데이터를 처리하고 조작하기 위한 방법을 제공하는 API
- 파일 입출력의 Stream과는 다른 개념이다!
- 람다식을 활용할 수 있다.
특징
- 배열, 컬렉션, 파일에 저장된 데이터 등을 모두 같은 방법으로 다룰 수 있다.
- 컬렉션에 저장된 요소들을 하나씩 순회하면서 처리할 수 있다.
- 외부 반복을 통해 작업하는 컬렉션과 달리 내부 반복(internal iteration)을 통해 작업을 수행한다.
- 스트림은 재사용이 가능한 컬렉션과 달리 단 한 번만 사용할 수 있다.
- 원본 데이터를 변경하지 않는다.
- 연산은 필터-맵(filter-map) 기반의 api를 사용하여 지연(lazy) 연산을 통해 성능을 최적화한다.
- 지연 연산 : 중간 처리 연산은 요청 시 수행되고, 최종 처리 연산을 호출할 때까지 데이터를 처리하지 않는다.
- parallelStream() 메소드들 통해 쉬운 병렬 처리를 지원한다.
- 스트림 동작 흐름 : 스트림의 생성->스트림의 중개 연산(스트림의 변환) -> 스트림의 최종 연산(스트림의 사용)

https://www.tcpschool.com/java/java_stream_concept
| 메소드 | 설명 |
|---|---|
concat(stream1, stream2) |
스트림1과 스트림2를 연결해서 새로운 스트림 생성 |
count() |
스트림의 모든 요소를 카운트 |
sum() |
스트림의 모든 요소를 합산 |
boxed() |
스트림의 기본 데이터 타입을 Wrapper 클래스로 변환 |
findFirst() |
스트림의 첫 번째 요소를 반환 |
- OptionalInt 클래스
| 메소드 | 설명 |
|---|---|
getAsInt() |
값이 존재하면 값을 반환, 없다면 NoSuchElementException 예외 반환 |
getAsDouble() |
getAsInt의 double형 반환 |
유의 사항
- IntStream을
List<Integer>로 변환하려면boxed()를 사용하여 int 타입을 Integer로 만들어야 한다. - 항상 스트림이 좋은 것은 아니다. 상황에 따라 다르다.
- 참고 자료 : June's 스트림은 항상 좋을까
- 스트림과 for-loop문을 비교했을 때 Collections보다 배열에서 for-loop가 압도적으로 빠르다.
- ArrayList와 같은 Collections에서는 순회하는 비용 자체가 워낙 크기 때문에 스트림과 for-loop의 차이가 이전에 비해 훨씬 많이 줄어든다.
- Wrapper type의 경우 기본 데이터 타입(primitive type)과 달리 스택 영역이 아닌 힙 영역에 저장된다.
- 스택 영역과 힙 영역은 메모리 구조 참고.
- 스택 영역에 저장된 간접 참조의 경우 힙에 객체의 내용이 있다면 중간에 그 곳을 가리키는 메모리 영역이 있고, 이 영역에서 참조해서 실제 힙의 주소를 얻은 후에 실제 힙의 내용을 참조한다.
- 하지만 스택 영역에 직접 저장되는 직접 참조의 경우엔 스택에 있는 변수에 힙 메모리의 실제 주소가 있기 때문에 직접 참조가 된다. 그래서 자주 참조되는 변수나 객체가 있다면 직접 참조가 더 빠르다.
- 그렇기에 Wrapper 타입은 힙 영역에 저장되므로, 스택 영역에 저장되서 직접 참조가 가능한 기본 타입과 달리 간접 참조를 통해 데이터를 가져와야 해서 참조 비용이 훨씬 비싸다.
- Wrapper 타입의 이런 특성 때문에 for-loop 컴파일의 최적화 이점이 사라져 for-loop보단 스트림에 적합하다.
- 스트림 사용이 for-loop보다 의미가 있으려면, Collection이 되는 스트림 소스의 크기가 충분히 크거나, 컴퓨팅 연산이 매우 좋아야 한다.